<template>
  <div class="photo-upload">
    <label class="el-button el-button--primary" for="group-upload">本地上传</label>
    <el-button type="success" @click="showCropper = true">裁剪上传</el-button>
    <el-button type="danger" @click="showNet = true">网络图上传</el-button>

    <!-- 本地上传 -->
    <input 
      ref="groupFile"
      type="file" 
      id="group-upload" 
      style="position:absolute; clip:rect(0 0 0 0);" 
      accept="image/*" 
      multiple 
      @change="onChooseImage($event)" 
    />
    <!-- 裁剪组件 -->
    <el-dialog 
      title="裁剪上传" 
      width="740px" 
      center :visible.sync="showCropper" 
      append-to-body
      :close-on-click-modal="false" 
    >
      <cropper 
        v-bind="$attrs" 
        :file-types="fileTypes" 
        :file-size="fileSize" 
        @cropFinish="onCropFinish" 
        @notCropFinish="onNotCropFinish" 
      />
    </el-dialog>
    <!-- 网络图上传 -->
    <el-dialog 
      title="网络图上传" 
      width="600px" 
      center :visible.sync="showNet" 
      append-to-body
      :close-on-click-modal="false" 
    >
      <el-input
        v-model="netUrls" 
        type="textarea" 
        :rows="8" 
        :minlength="10" 
        :maxlength="1000" 
        resize="none" 
        show-word-limit 
        clearable 
        placeholder="请粘贴网络图地址，多个以英文逗号【,】分割，不得有多余字符"
      />
      <div slot="footer" class="net-footer">
        <el-button type="text" @click="showNet = false">取 消</el-button>
        <el-button 
          type="primary" 
          :disabled="netDisabled" 
          :loading="newSaveLoading" 
          @click.native.prevent="onNetFinish"
        >确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import Cropper from '../Cropper'
import { mapMutations } from 'vuex'
import { upload, uploadMultiple } from '@/api/common'
import { photoCreate } from '@/api/photo'
import { checkFileType, checkFileSize, isStrEmpty, isNetImage } from '@/utils/validate'
import { uniqueArray } from '@/utils/util'

export default {
  name: 'PhotoUpload',
  components: { Cropper },
  props: {
    // 单次最多上传数
    oneUpCount: {
      type: Number,
      default: 20
    },
    // 上传文件夹
    dirName: {
      type: String,
      default: 'group'
    },
    // 文件类型
    fileTypes: {
      type: Array,
      default: () => ['jpg','png','jpeg','webp','gif']
    },
    // 文件大小限制(Mb)
    fileSize: {
      type: Number,
      default: 1
    },
    // 分类切换
    photoGroupId: {
      type: Number,
      default: null
    },
  },
  computed: {
    netDisabled() {
      return isStrEmpty(this.netUrls)
    },
  },
  data() {
    return {
      showCropper: false,
      showNet: false,
      netUrls: '',
      newSaveLoading: false
    }
  },
  methods: {
    loadingOptions(count = 1) {
      return {
        target: '.photo-group',
        text: `正在上传 ${count} 个文件`
      }
    },
    /**
     * 1、裁剪完成
     * fileType 裁剪返回类型 blob数据 base64数据
     * fileName 文件名
     * data     blob数据或base64数据 
     * fileSuffix 文件后缀（含.）
     */
    onCropFinish(result) {
      const { fileName, data } = result
      // 将 blob 转为 file 对象【base64未实现】
      const file = new File([data], fileName, { type: data.type })

      this.showCropper = false
      this.onUpload(file)
    },
    /**
     * 2、不裁剪 直接上传
     */
    onNotCropFinish(result) {
      const { file } = result
      this.showCropper = false
      this.onUpload(file)
    },
    /**
     * 3、选择本地图片 直接上传
     */
    onChooseImage(event) {
      const { files } = event.target

      // 如果是多选文件 判断选择的数量是否超出上传限制
      if (files.length > this.oneUpCount) {
        this.$notify.warning({
          title: "警告",
          message: `单次最多选择${this.oneUpCount}个文件`,
          duration: 2000,
        });
        this.$refs.groupFile.value = null
        return false
      }

      for (const file of files) {
        // 校检格式
        if (!checkFileType(file, 'image', this.fileTypes)) {
          this.$notify.warning({
            title: "警告",
            message: `请上传${this.fileTypes.join('/')}格式图片`,
            duration: 2000,
          });
          this.$refs.groupFile.value = null
          return false
        }
        // 校检文件大小
        if (!checkFileSize(file, this.fileSize)) {
          this.$notify.warning({
            title: "警告",
            message: `请上传${this.fileSize}MB以内图片`,
            duration: 2000,
          });
          this.$refs.groupFile.value = null
          return false 
        }
      }
      
      this.onUploadMultiple(files)
    },
    /**
     * 4、网路图上传
     */
    async onNetFinish() {
      try {
        this.newSaveLoading = true
        // 图片地址字符串转为数组
        const urls = this.netUrls.split(',')
        // 图片地址数组去重
        const uniqueUrls = uniqueArray(urls)
        // 循环判断合法性
        for (const url of uniqueUrls) {
          await isNetImage(url.replace(/\s+/g, ''))
        }
        // 上传图片表
        const { data } = await photoCreate({
          urls: uniqueUrls.join(),
          photo_group_id: this.photoGroupId,
          from: 1,
        })
        this.pushPhotoList(data)
        this.pushPhotoTotal(data.length)
        this.showNet = false
      } catch (error) {
        this.$notify.error({
          title: '错误',
          message: error.message,
          duration: 3000,
          customClass: 'neturl-error'
        })
      } finally {
        this.newSaveLoading = false
      }
    },
    // 上传单张
    async onUpload(file) {
      const loadingInstance = this.$loading(this.loadingOptions())
      try {
        const { info } = await upload(file, this.dirName)
        this.setList([info.url])
      } finally {
        loadingInstance.close()
      }
    },
    // 上传多张
    async onUploadMultiple(files) {
      const loadingInstance = this.$loading(this.loadingOptions(files.length))
      try {
        const { data } = await uploadMultiple(files, this.dirName)
        this.setList(data)
      } finally {
        loadingInstance.close()
        this.$refs.groupFile.value = null
      }
    },
    ...mapMutations('upload', {
      setList: 'SET_LIST',
    }),
    ...mapMutations('photoGroupImage', {
      pushPhotoList: 'PUSH_PHOTO_LIST',
      pushPhotoTotal: 'PUSH_PHOTO_TOTAL',
    }),
  },
}
</script>

<style lang="scss">
.neturl-error {
  .el-notification__content {
    word-break: break-all;
  }
}
</style>

<style lang="scss" scoped>
.photo-upload {
  flex: auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
</style>